#ifndef _EG_DATA
#define _EG_DATA 1

/*
 * File:    eg_data.h
 * Purpose: Common data structures used in the ElectroGladiator programs
 */

/*
 Copyright 2009 James Youngquist, Colin Scott.

 This file is part of ElectroGladiator.  ElectroGladiator is free
 software: you can redistribute it and/or modify it under the terms
 of the GNU General Public License as published by  the Free
 Software Foundation, either version 3 of the License, or (at your
 option) any later version.

 You should have received a copy of the GNU General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <stdlib.h>

//-------
// MACROS
//-------

#define POINT  &print_point
#define LINE   &print_line
#define TRIGON &print_trigon
#define PLAYER &print_player
#define ROCK   &print_rock
#define P_SPEED 1.0
#define R_SPEED 10.0
#define P_RAD 0.50
#define R_RAD 0.25

//----------------
// DATA STRUCTURES
//----------------

typedef void (*ll_printer)(void*); /* function pointer */

/** Linked lists */
typedef struct Node {
    void        *data;          /* nature abhors a vacuum */
    struct Node *next;          /* next node in list      */

} Node;

typedef struct LL {
    Node *front;                /* front of the list                   */
    int length;                 /* number of elements in the list      */
    ll_printer printer;         /* function which knows how to print a *
                                 * node's data, LLs are monotypical.   */
} LL;

/** Represents a point */
typedef struct Point {
    double x;
    double y;
} Point;

/** Represents a line */
typedef struct Line {
    Point p1;                   /* Each point is an endpoint */
    Point p2;
} Line;

/** Represents a vision triangle */
typedef struct Trigon {
    Point p1;                   /* Each point is a vertex. P1-P2 is segment */
    Point p2;                   /* A, P2-P3 is segment B and P3-P1 is C.    */
    Point p3;
} Trigon;

/** Represents a player */
typedef struct Player {
    Point  location;           /* x,y >= 0.  All play is in first quadrant */
    double bearing;            /* where 0 is along the positive x-axis     */
    LL    visible_lines;       /* line segments the player can see         */
    LL    vision_triangles;    /* player's current vision triangles        */
    LL    visible_players;     /* other players this player can see        */
    LL    visible_rocks;       /* all projectiles this player can see      */
    int   PID;                 /* ID number associated with this player    */
} Player;

/** Represents a projectile */
typedef struct Rock {
    Point location;       // x,y >= 0.
    double bearing;       // where - is along the positive x-axis
    double speed;         // units per tick
    Player *owner;        // which player flung it
} Rock;

/** Represents the map */
typedef struct Map {
    double width;	   /* width of the map                      */
    double height;	   /* height of the map                     */
    int num_lines;	   /* number of lines, including boundaries */
    Line **lines;	   /* pointer to array of Lines             */
    int num_players;   /* number of players                     */
    Player **players;  /* pointer to array of players           */
	LL rocks;          /* all projectiles on the map            */
	// The number of rocks is stored in LL->length
} Map;



//--------------------
// FUNCTION PROTOTYPES
//--------------------

/* Sets up a local linked list for use */
void ll_init (LL* list, ll_printer p);

/* Treats linked list as a queue and prepends data to the front.
 * Returns a pointer to the added node.
 */
Node* ll_push (LL* list, void* data);

/* Treats linked list as a queue and removes frontmost data.
 * Returns pointer to removed data or NULL if empty.
 */
void* ll_pop (LL* list);

/* Returns number of elements in the linked list. */
int ll_length (const LL* list);

/* Sorts a list of points according to their distance from p */
void ll_point_sort (LL* list, const Point *p);

/* Pretty prints a linked list */
void ll_print (const LL* list);

/**
 * Removes the node from the list and returns the data that was stored therein.
 * @param list Linked list to remove node from
 * @param node Node to remove from list
 */
void* ll_rm_node(LL *list, Node *node);

/* Frees memory used by a linked list.
 * Pre: All nodes and node data were allocated on the heap and can be free()'d
 */
void ll_clear (LL* list);

/*
 * Returns a pointer to the data stored at
 * the given index. Prints an error message
 * and returns NULL if the index is incorrect.
 */
void* ll_get(LL* list, int index);

/* 
 * Iterator for linked lists Part I. This function is called
 * first and returns a pointer to the first node in the LL,
 * or NULL if the list is empty or the LL is NULL to begin with
 */
Node* ll_itr_first (const LL* list);

/*
 * Iterator for linked lists Part 2. This function is the
 * normal itr.next function in OOP.
 */
void* ll_itr_next (const Node* curr);


// CONSTRUCTORS and DESTRUCTORS.
// All new_* functions allocate on the heap.

/* Creates a new Node on the heap initialized with the arguments */
Node* new_node (void *data, Node *next);

/* Creates a new Point on the heap initialized with the arguments */
Point* new_point (double x, double y);

/* Creates a new Line on the heap initialized with the arguments */
Line* new_line (double x1, double y1, double x2, double y2);

// Creates a ray of specified length and starting point, allocated on the heap
Line* make_ray(const Point *start, double angle, double length);

/* Creates a new Trigon on the heap initialized with the arguments */
Trigon* new_trigon (Point p1, Point p2, Point p3);

/* Creates a new Player on the heap initialized with the arguments */
Player* new_player (double x, double y, double bearing);

/* Creates a new Rock on the heap */
Rock* new_rock(double x, double y, double bearing, Player *owner);

/* Frees memory used by a Node, but not the data it contains. */
void free_node (Node *n);

// FREEING

/* Frees ALL memory used by a Node including the data it contains. */
void eradicate_node (Node *n);

/* Frees memory used by a Point.
 * Currently no points are needed by themselves, so none need be on the heap.
 */
void free_point (Point* p);

/* Frees memory used by a Line */
void free_line (Line* l);

/* Frees memory used by a Trigon */
void free_trigon (Trigon* t);

/* Frees memory used by a Player */
void free_player (Player *p);

/* Frees memory used by a Rock */
void free_rock (Rock *r);

// PRINTING

/* displays (x, y) */
void print_point (void* p);

/* displays [(x1, y1)--(x2, y2)] */
void print_line (void* l);

/* displays <(x1, y1)^^(x2, y2)^^(x3, y3)> */
void print_trigon (void* t);

/* displays {(x, y) @ bearing} */
void print_player (void* p);

/** Displays ! A rock thrown by PID is at (x, y) with bearing N.NNN */
void print_rock(void* r);

// OTHER

/**
 * @return Returns next PID number
 */
int next_PID (void);

// Usable AlmostEqual function
// From
// http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm
// and modified for doubles and longs
int fnear(double A, double B);

// PRIVATE

Point* place_rock (Player *owner);

#endif
